'''
机器学习图像分类
'''
from .base_stats import * 
from .base_image import *
from sklearn import datasets
import cv2

'''
用统计的方式对图像的每个点进行分布拟合，并对测试图像进行分类
'''
class ImageDistribution(Distributions):
	'''
	图片的分布
	'''
	def __init__(self, xSize:int=8, ySize:int=8, valueMax:float=16):
		super().__init__(0, valueMax)
		self.dists = []
		self.xSize = xSize
		self.ySize = ySize
		for i in range(xSize):
			for j in range(ySize):
				self.dists.append(Distribution(0, valueMax))

	def append_pixel(self, x: float, y: float, pixel: float):
		dist = self.dists[int(x)*self.ySize+int(y)]
		dist.append_data(pixel)
		super().append_data(pixel)

	def to_image(self)-> list[list[float]]:
		image: list[list[float]] = [[0 for y in range(self.ySize)] for x in range(self.xSize)]
		for x in range(self.xSize):
			for y in range(self.ySize):	
				pixel = self.dists[x*self.ySize+y].median
				image[x][y] = pixel
		return image
	
	def calc_deviation_by_image(self, image, type: str = 'median'):
		'''
		计算离散度
		'''
		divation: FloatOrArray = 0
		for x in range(self.xSize):
			for y in range(self.ySize):
				pixel = image[x][y]
				dist = self.dists[x*self.ySize+y]
				divation += dist.calc_deviation(pixel, type)
		return divation / (self.xSize * self.ySize)

class ImageClassifier():
	'''
	图像分类器
	'''
	def __init__(self, xSize:int=8, ySize:int=8, valueMax:float=16):
		self.xSize = xSize
		self.ySize = ySize
		self.valueMax = valueMax
		self.distributes: dict[int, ImageDistribution] = {}
		self.dist: ImageDistribution = ImageDistribution(xSize, ySize, valueMax)

	def learn(self, targets: list[int], images: list[np.ndarray])->None:
		'''
		使用监督学习对图像进行分类
		'''
		# 为每个图像生成分布
		dist_count = len(targets)			
		for i in range(dist_count):
			target = targets[i]
			image = images[i]
			dist_image = ImageDistribution(self.xSize, self.ySize, self.valueMax) if target not in self.distributes else self.distributes[target]
			self.distributes[target] = dist_image
			for x in range(self.xSize):
				for y in range(self.ySize):
					pixel = image[x, y]
					dist_image.append_pixel(x, y, pixel)
					self.dist.append_data(x, y, pixel)

	def calc_deviations_by_image(self, image) -> list[tuple[int, FloatOrArray]]:
		'''
		获取单张图像的偏差列表
		'''
		deviations = [(key, dist.calc_deviation_by_image(image, 'median')) for key, dist in self.distributes.items()]
		def cmp(x):
			return x[1]
		deviations.sort(key=cmp)
		return deviations
	
	def test_image(self, image):
		'''
		测试单张图像
		'''
		deviations = self.calc_deviations_by_image(image)
		div_target = deviations[0][0]
		divation = deviations[0][1]
		return div_target, divation, deviations
	
	def plot_simulated_image(self):
		'''
		绘制模拟图像
		'''
		plt.subplots_adjust(hspace=1)
		for target, feature in self.distributes.items():
			plt.subplot(5, 2, target+1)
			img = feature.to_image()
			plt.imshow(img, cmap='gray_r')
			plt.title(f"{target} 模拟")

	def normalize_image(self, image):
		'''
		归一化图像
		'''
		# 将图像大小缩小为8X8
		normalized_image = cv2.resize(normalized_image, (self.xSize, self.ySize))
		# 将图像中所有点的值的平均值调整为与本地图像的平均值一致
		mean = np.mean(image)
		normalized_image = image * self.dist.mean / mean
		return normalized_image